import { initializeApp } from 'firebase/app'
import {
  type AuthProvider,
  browserLocalPersistence,
  FacebookAuthProvider,
  getAuth,
  getRedirectResult,
  GoogleAuthProvider,
  OAuthCredential,
  OAuthProvider,
  setPersistence,
  signInWithPopup,
  signInWithRedirect,
  signOut
} from 'firebase/auth'
import { getToken, initializeAppCheck, onTokenChanged, ReCaptchaV3Provider } from 'firebase/app-check'
import { browserSessionPersistence, type UserCredential } from '@firebase/auth'
import { FirebaseError } from '@firebase/util'

/**
 * Firebase配置
 */
const firebaseConfig = {
  apiKey: import.meta.env.SP_FIREBASE_API_KEY,
  authDomain: import.meta.env.SP_FIREBASE_AUTH_DOMAIN,
  projectId: import.meta.env.SP_FIREBASE_PROJECT_ID,
  storageBucket: import.meta.env.SP_FIREBASE_STORAGE_BUCKET,
  messagingSenderId: import.meta.env.SP_FIREBASE_MESSAGING_SENDER_ID,
  appId: import.meta.env.SP_FIREBASE_APP_ID,
  measurementId: import.meta.env.SP_FIREBASE_MEASUREMENT_ID
}

const firebaseApp = initializeApp(firebaseConfig)

export const firebaseAuth = getAuth(firebaseApp)

export const FIREBASE_APPCHECK_DEBUG_TOKEN = import.meta.env.DEV
const appCheck = initializeAppCheck(firebaseApp, {
  provider: new ReCaptchaV3Provider(import.meta.env.SP_RECAPTCHA_SITE_KEY),
  isTokenAutoRefreshEnabled: true
})

/**
 * 获取AppCheck's Token
 *
 * @param forceRefresh 是否强制刷新Token
 */
export async function getAppCheckToken(forceRefresh?: boolean) {
  try {
    return (await getToken(appCheck, forceRefresh)).token
  } catch (e) {
    return null
  }
}

/**
 * AppCheck Token 发生变化
 * @param onChanged
 */
export function onAppCheckTokenChanged(onChanged: (acToken: string) => void) {
  onTokenChanged(appCheck, tokenResult => onChanged(tokenResult.token))
}

export enum AppAuthProvider {
  Google, Apple, Facebook
}

/**
 * 登录
 * @param appAuthProvider 使用哪种登录授权提供商
 * @param enableLocalPersistence 是否使用本地持久性的状态持久化，默认使用本地存储
 * @throws FirebaseError
 */
export async function firebaseLogin(appAuthProvider: AppAuthProvider, enableLocalPersistence: boolean = true, enableSignInWithPopup: boolean = true) {
  const persistence = enableLocalPersistence ? browserLocalPersistence : browserSessionPersistence
  let provider: AuthProvider
  let credentialFromResult: (userCredential: UserCredential) => OAuthCredential | null
  let credentialFromError: (error: FirebaseError) => OAuthCredential | null
  switch (appAuthProvider) {
    case AppAuthProvider.Google:
      provider = new GoogleAuthProvider()
      credentialFromResult = GoogleAuthProvider.credentialFromResult
      credentialFromError = GoogleAuthProvider.credentialFromError
      break
    case AppAuthProvider.Apple:
      provider = new OAuthProvider('apple.com')
      credentialFromResult = OAuthProvider.credentialFromResult
      credentialFromError = OAuthProvider.credentialFromError
      break
    case AppAuthProvider.Facebook:
      provider = new FacebookAuthProvider()
      credentialFromResult = FacebookAuthProvider.credentialFromResult
      credentialFromError = FacebookAuthProvider.credentialFromError
      break
  }

  try {
    await setPersistence(firebaseAuth, persistence)
    let userCredential: UserCredential | null
    if (enableSignInWithPopup) {
      userCredential = await signInWithPopup(firebaseAuth, provider)
    } else {
      await signInWithRedirect(firebaseAuth, provider)
      userCredential = await getRedirectResult(firebaseAuth)
      if (!userCredential) {
        throw 'getRedirectResult extract fail, credential is null'
      }
    }
    const oAuthCredential = credentialFromResult(userCredential)
    if (!oAuthCredential) {
      throw 'Provider.credentialFromResult extract fail, credential is null'
    }
    return { userCredential, oAuthCredential }
  } catch (error) {
    if (error instanceof FirebaseError) {
      const errorCode = error.code
      const errorMessage = error.message
      const email = error.customData?.email
      const credential = credentialFromError(error)
      console.error(`FirebaseAuth: ${errorCode} - ${errorMessage}`)
    }
    throw error
  }
}

/**
 * 退出账户
 */
export async function firebaseSignOut() {
  return signOut(firebaseAuth)
}

/**
 * 获取当前登录的用户
 */
export function getCurrentUser() {
  return firebaseAuth.currentUser
}